﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Xml;
using System.IO;
using System.Web;
using System.Net;
using System.Web.Script.Serialization;
using System.Threading;

namespace AliCMS.CourseModule.Bll
{
    public class InstanceConfig : XmlObjectBase, IInstanceConfig
    {
        public InstanceConfig(int instanceID, string lang, bool checkRight, string database)
            : base(instanceID, lang, checkRight)
        {
            string dir = Manager.MapPath(Manager.GetDataPath(instanceID, Lang));
            Manager.MakeSureFolderExist(dir);
            string path = dir + "instance.config";
            if (!File.Exists(path))
            {
                XmlDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\" ?><configuration></configuration>");
                Save();
                return;
            }
            else
            {
                XmlDoc.Load(path);
            }
        }

        public override object ExecuteService(HttpContext context)
        {
            object result = null;

            string operation = context.Request.QueryString["Operation"];
            if (operation == "SetBasicSettings")
            {
                Dictionary<string, string> item = new Dictionary<string, string>();
                string value = null;
                value = context.Request.Form["CourseThumbnailWidth"];
                if (value != null) item[Alias.InstanceConfig.CourseThumbnailWidth] = value;
                value = context.Request.Form["CourseThumbnailHeight"];
                if (value != null) item[Alias.InstanceConfig.CourseThumbnailHeight] = value;
				value = context.Request.Form["OnlinePayNotifyUrl"];
				if (value != null) item[Alias.InstanceConfig.OnlinePayNotifyUrl] = value;
                value = context.Request.Form["MemberOnlinePayNotifyUrl"];
                if (value != null) item[Alias.InstanceConfig.MemberOnlinePayNotifyUrl] = value;

                SetBasicSettings(item);
                Save();
            }
            else if (operation == "GetJsApiTicket")
            {
                result = GetJsApiTicket();
            }
            else if (operation == "BuildQRCode")
            {
                result = BuildQRCode(context.Request.QueryString["Text"], context.Request.QueryString["Logo"]);
            }
            else
            {
                throw new Exception("lang_header_param");
            }

            return result;
        }

        public Dictionary<string, string> GetBasicSettings()
        {
            if (CheckRight)
            {
                ValidateRight("GetBasicSettings", Guid.Empty);
            }

            Dictionary<string, string> result = new Dictionary<string, string>();

            XmlNode basic = XmlDoc.SelectSingleNode("//BasicSettings");
            if (basic == null)
            {
                result[Alias.InstanceConfig.CourseThumbnailWidth] = "250";
                result[Alias.InstanceConfig.CourseThumbnailHeight] = "250";
				result[Alias.InstanceConfig.OnlinePayNotifyUrl] = String.Empty;
                result[Alias.InstanceConfig.MemberOnlinePayNotifyUrl] = String.Empty;
            }
            else
            {
                XmlNode node = null;

                node = basic.SelectSingleNode("CourseThumbnailWidth");
                if (node == null)
					result[Alias.InstanceConfig.CourseThumbnailWidth] = "250";
                else
                    result[Alias.InstanceConfig.CourseThumbnailWidth] = node.InnerText;

                node = basic.SelectSingleNode("CourseThumbnailHeight");
                if (node == null)
					result[Alias.InstanceConfig.CourseThumbnailHeight] = "250";
                else
                    result[Alias.InstanceConfig.CourseThumbnailHeight] = node.InnerText;

				node = basic.SelectSingleNode("OnlinePayNotifyUrl");
                if (node == null)
					result[Alias.InstanceConfig.OnlinePayNotifyUrl] = String.Empty;
                else
					result[Alias.InstanceConfig.OnlinePayNotifyUrl] = node.InnerText;

                node = basic.SelectSingleNode("MemberOnlinePayNotifyUrl");
                if (node == null)
                    result[Alias.InstanceConfig.MemberOnlinePayNotifyUrl] = String.Empty;
                else
                    result[Alias.InstanceConfig.MemberOnlinePayNotifyUrl] = node.InnerText;
            }

            return result;
        }
        public void SetBasicSettings(Dictionary<string, string> value)
        {
            if (CheckRight)
            {
                ValidateRight("SetBasicSettings", Guid.Empty);
            }

            XmlNode node = null;
            XmlNode basic = XmlDoc.SelectSingleNode("//BasicSettings");
            if (basic == null)
            {
                basic = XmlDoc.CreateElement("BasicSettings");
                XmlDoc.DocumentElement.AppendChild(basic);
            }

            if (value.ContainsKey(Alias.InstanceConfig.CourseThumbnailWidth))
            {
                node = basic.SelectSingleNode("CourseThumbnailWidth");
                if (node == null)
                {
                    node = XmlDoc.CreateElement("CourseThumbnailWidth");
                    basic.AppendChild(node);
                }
                if (String.IsNullOrEmpty(value[Alias.InstanceConfig.CourseThumbnailWidth]))
                    basic.RemoveChild(node);
                else
                    node.InnerText = value[Alias.InstanceConfig.CourseThumbnailWidth];
            }

            if (value.ContainsKey(Alias.InstanceConfig.CourseThumbnailHeight))
            {
                node = basic.SelectSingleNode("CourseThumbnailHeight");
                if (node == null)
                {
                    node = XmlDoc.CreateElement("CourseThumbnailHeight");
                    basic.AppendChild(node);
                }
                if (String.IsNullOrEmpty(value[Alias.InstanceConfig.CourseThumbnailHeight]))
                    basic.RemoveChild(node);
                else
                    node.InnerText = value[Alias.InstanceConfig.CourseThumbnailHeight];
            }

			if (value.ContainsKey(Alias.InstanceConfig.OnlinePayNotifyUrl))
			{
				string oldUrl = String.Empty;
				string newUrl = value[Alias.InstanceConfig.OnlinePayNotifyUrl];

				node = basic.SelectSingleNode("OnlinePayNotifyUrl");
				if (node == null)
				{
					node = XmlDoc.CreateElement("OnlinePayNotifyUrl");
					basic.AppendChild(node);
				}
				else
				{
					oldUrl = node.InnerText;
				}

				if (String.IsNullOrEmpty(value[Alias.InstanceConfig.OnlinePayNotifyUrl]))
					basic.RemoveChild(node);
				else
					node.InnerText = value[Alias.InstanceConfig.OnlinePayNotifyUrl];

				#region 更新Rewrite（网址重写）
				if (oldUrl != newUrl)
				{
					DataRow[] rows = Manager.Instances.Select(SystemModule.Alias.Instance.InnerID + "=" + InstanceID);
					object instanceID = rows[0][SystemModule.Alias.Instance.ID];

					using (SystemModule.IRewrite bll = (SystemModule.IRewrite)Manager.CreateObject("Rewrite", 0, Lang, false))
					{
						#region 删掉原来的记录
						if (!String.IsNullOrEmpty(oldUrl))
						{
							DataTable table = bll.List(-1, -1, SystemModule.Alias.Rewrite.InstanceID + "=" + instanceID + " AND " + SystemModule.Alias.Rewrite.ObjectFullName + "='Order' AND " + SystemModule.Alias.Rewrite.Operation + "='OnlinePayNotify' AND " + SystemModule.Alias.Rewrite.Lang + "='" + Lang + "'", null);
							foreach (DataRow row in table.Rows)
							{
								bll.Delete((int)row[SystemModule.Alias.Rewrite.InnerID]);
							}
						}
						#endregion

						#region 增加新记录
						if (!String.IsNullOrEmpty(newUrl))
						{
							Dictionary<string, object> item = new Dictionary<string, object>();
							item[SystemModule.Alias.Rewrite.LookFor] = newUrl.Replace(".", @"\.");
							item[SystemModule.Alias.Rewrite.Type] = "Instance";
							item[SystemModule.Alias.Rewrite.InstanceID] = instanceID;
							item[SystemModule.Alias.Rewrite.ObjectFullName] = "Order";
							item[SystemModule.Alias.Rewrite.Operation] = "OnlinePayNotify";
							item[SystemModule.Alias.Rewrite.Lang] = Lang;
							bll.Add(item);
						}
						#endregion
					}
				}
				#endregion
			}

            if (value.ContainsKey(Alias.InstanceConfig.MemberOnlinePayNotifyUrl))
            {
                string oldUrl = String.Empty;
                string newUrl = value[Alias.InstanceConfig.MemberOnlinePayNotifyUrl];

                node = basic.SelectSingleNode("MemberOnlinePayNotifyUrl");
                if (node == null)
                {
                    node = XmlDoc.CreateElement("MemberOnlinePayNotifyUrl");
                    basic.AppendChild(node);
                }
                else
                {
                    oldUrl = node.InnerText;
                }

                if (String.IsNullOrEmpty(value[Alias.InstanceConfig.MemberOnlinePayNotifyUrl]))
                    basic.RemoveChild(node);
                else
                    node.InnerText = value[Alias.InstanceConfig.MemberOnlinePayNotifyUrl];

                #region 更新Rewrite（网址重写）
                if (oldUrl != newUrl)
                {
                    DataRow[] rows = Manager.Instances.Select(SystemModule.Alias.Instance.InnerID + "=" + InstanceID);
                    object instanceID = rows[0][SystemModule.Alias.Instance.ID];

                    using (SystemModule.IRewrite bll = (SystemModule.IRewrite)Manager.CreateObject("Rewrite", 0, Lang, false))
                    {
                        #region 删掉原来的记录
                        if (!String.IsNullOrEmpty(oldUrl))
                        {
                            DataTable table = bll.List(-1, -1, SystemModule.Alias.Rewrite.InstanceID + "=" + instanceID + " AND " + SystemModule.Alias.Rewrite.ObjectFullName + "='MemberOrder' AND " + SystemModule.Alias.Rewrite.Operation + "='OnlinePayNotify' AND " + SystemModule.Alias.Rewrite.Lang + "='" + Lang + "'", null);
                            foreach (DataRow row in table.Rows)
                            {
                                bll.Delete((int)row[SystemModule.Alias.Rewrite.InnerID]);
                            }
                        }
                        #endregion

                        #region 增加新记录
                        if (!String.IsNullOrEmpty(newUrl))
                        {
                            Dictionary<string, object> item = new Dictionary<string, object>();
                            item[SystemModule.Alias.Rewrite.LookFor] = newUrl.Replace(".", @"\.");
                            item[SystemModule.Alias.Rewrite.Type] = "Instance";
                            item[SystemModule.Alias.Rewrite.InstanceID] = instanceID;
                            item[SystemModule.Alias.Rewrite.ObjectFullName] = "MemberOrder";
                            item[SystemModule.Alias.Rewrite.Operation] = "OnlinePayNotify";
                            item[SystemModule.Alias.Rewrite.Lang] = Lang;
                            bll.Add(item);
                        }
                        #endregion
                    }
                }
                #endregion
            }
        }

        public string GetJsApiTicket()
        {
            HttpRequest req = HttpContext.Current.Request;
            string url = req.UrlReferrer.ToString().Split(new char[] { '#' })[0];

            HttpWebRequest request = null;
            HttpWebResponse response = null;
            StreamReader sr = null;
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            Dictionary<string, object> json = null;
            String result = null;

            #region accessToken
            string accessToken = null;
            string appId = Manager.Site[SystemModule.Alias.InstanceConfig.WxppAppID + Lang];
            string appSecret = Manager.Site[SystemModule.Alias.InstanceConfig.WxppAppSecret + Lang];

            accessToken = GetAccessToken(appId, appSecret);
            if (accessToken == null)
            {
                Manager.Log("CourseModule - InstanceConfig - GetJsApiTicket - 1", "accessToken == null", Lang);
                return "{\"error\":1,\"errmsg\":\"access token is null!\"}";
            }
            #endregion

            #region 获取jsApiTicket
            request = (HttpWebRequest)WebRequest.Create("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=jsapi");
            request.Timeout = 15 * 1000;
            response = (HttpWebResponse)request.GetResponse();
            sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
            result = sr.ReadToEnd().Trim();
            sr.Close();

            json = serializer.DeserializeObject(result) as Dictionary<string, object>;
            if (Convert.ToInt32(json["errcode"]) != 0)
            {
                result = "{\"error\":6,\"errcode\":" + json["errcode"] + ",\"errmsg\":\"" + json["errmsg"] + "\"}";
                Manager.Log("CourseModule - InstanceConfig - GetJsApiTicket - 6", result, Lang);
                return result;
            }
            string ticket = json["ticket"].ToString();
            #endregion

            #region 签名
            string nonceStr = UserModule.WxPayPartner.GetNonceStr();
            long timestamp = UserModule.WxPayPartner.GetTimestamp();
            string sign = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "&timestamp=" + timestamp + "&url=" + url;
            sign = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sign, "SHA1");
            #endregion

            return "{\"error\":0,\"appId\":\"" + appId + "\",\"timestamp\":\"" + timestamp + "\",\"nonceStr\":\"" + nonceStr + "\",\"signature\":\"" + sign + "\"}";
        }
        public string GetAccessToken(string appId, string appSecret)
        {
            string dir = Manager.MapPath(Manager.GetDataPath(InstanceID, null)) + "access_token/";
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);

            int counter = 0;
            string lockFile = dir + appId + ".lock";
            while (File.Exists(lockFile))
            {
                if (counter == 5)
                {
                    if (DateTime.Now.Subtract(File.GetCreationTime(lockFile)).Minutes > 1)
                    {
                        File.Delete(lockFile);
                        break;
                    }

                    return null;
                }

                Thread.Sleep(1000);//等待一秒
                counter++;
            }

            string token = null;
            DateTime expiredTime = DateTime.MinValue;
            JavaScriptSerializer serializer = new JavaScriptSerializer();

            try
            {
                _logWriteLock.EnterWriteLock();

                //创建锁定文件
                File.Create(lockFile).Close();

                string path = dir + appId + ".txt";
                if (File.Exists(path))
                {
                    Dictionary<string, object> json = serializer.DeserializeObject(File.ReadAllText(path)) as Dictionary<string, object>;
                    token = json["token"].ToString();
                    if (json["expiredTime"].ToString() != "")
                        expiredTime = Convert.ToDateTime(json["expiredTime"].ToString());
                }

                if (String.IsNullOrEmpty(token) || expiredTime.Subtract(DateTime.Now).TotalMinutes < 5)
                {
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret);
                    request.Timeout = 15 * 1000;
                    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                    StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                    String result = sr.ReadToEnd().Trim();
                    sr.Close();

                    Dictionary<string, object> json = serializer.DeserializeObject(result) as Dictionary<string, object>;
                    if (!json.ContainsKey("access_token"))
                    {
                        Manager.Log("CourseModule - GetAccessToken - get", "appId：" + appId + "\r\nResult：" + result, Lang);
                        return null;
                    }

                    token = json["access_token"].ToString();
                    expiredTime = DateTime.Now.AddSeconds(Convert.ToInt32(json["expires_in"]));
                    File.WriteAllText(path, "{\"token\":\"" + token + "\",\"expiredTime\":\"" + expiredTime.ToString() + "\"}");
                }
            }
            catch (Exception exp)
            {
                Manager.Log("CourseModule - GetAccessToken", "appId：" + appId + "\r\nException：" + exp.ToString(), Lang);
            }
            finally
            {
                File.Delete(lockFile);
                _logWriteLock.ExitWriteLock();
            }

            return token;
        }
        public string BuildQRCode(String text, String logo)
        {
            if (String.IsNullOrEmpty(text))
                return "";

            //将字符串生成二维码图片
            String name = text.Replace('\\', '_').Replace('/', '_').Replace(':', '_').Replace('*', '_').Replace('?', '_').Replace('"', '_').Replace('<', '_').Replace('>', '_').Replace('|', '_').Replace('.', '_').Replace('=', '_').Replace('&', '_');
            if (name.Length > 200)
                name = name.Substring(name.Length - 200);
            String path = Manager.GetCachePath() + "qrcode/" + name + ".jpg";
            String filePath = Manager.MapPath(path);
            if (File.Exists(filePath))
                return path;

            //创建生成器
            ThoughtWorks.QRCode.Codec.QRCodeEncoder qrCodeEncoder = new ThoughtWorks.QRCode.Codec.QRCodeEncoder();
            qrCodeEncoder.QRCodeEncodeMode = ThoughtWorks.QRCode.Codec.QRCodeEncoder.ENCODE_MODE.BYTE;
            qrCodeEncoder.QRCodeErrorCorrect = ThoughtWorks.QRCode.Codec.QRCodeEncoder.ERROR_CORRECTION.M;
            qrCodeEncoder.QRCodeVersion = 0;
            qrCodeEncoder.QRCodeScale = 8;

            System.Drawing.Bitmap image = qrCodeEncoder.Encode(text, Encoding.Default);
            if (!String.IsNullOrEmpty(logo) && logo.StartsWith("/") && File.Exists(Manager.MapPath(logo)))
            {
                System.Drawing.Image img = System.Drawing.Image.FromFile(Manager.MapPath(logo));
                int size = 50;
                if (img.Height != size || img.Width != size)
                {
                    try
                    {
                        System.Drawing.Image b = new System.Drawing.Bitmap(size, size);
                        System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(b);
                        // 插值算法的质量  
                        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                        g.DrawImage(img, new System.Drawing.Rectangle(0, 0, size, size), new System.Drawing.Rectangle(0, 0, img.Width, img.Height), System.Drawing.GraphicsUnit.Pixel);
                        g.Dispose();

                        img = b;
                    }
                    catch
                    {
                        img = null;
                    }
                }

                if (img != null)
                {
                    System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(image);
                    g.DrawImage(image, 0, 0, image.Width, image.Height);//【注】这一行应该是多余的吧？因为，没有测试，暂时未删除。
                    g.DrawImage(img, image.Width / 2 - img.Width / 2, image.Width / 2 - img.Width / 2, img.Width, img.Height);
                    GC.Collect();
                }
            }

            //保存
            image.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);

            //
            return path;
        }


        public void Save()
        {
            string path = Manager.MapPath(Manager.GetDataPath(InstanceID, Lang));
            Manager.MakeSureFolderExist(path);

            XmlDoc.Save(path + "instance.config");
        }

        #region Fields
        public static ReaderWriterLockSlim _logWriteLock = new ReaderWriterLockSlim();
        #endregion
    }
}
